import logging
from accounts.models import ExpLog
from django.contrib.auth.models import User
from django.db import models
from django.db.models.signals import post_delete, post_save
from django.dispatch import receiver
from django.utils import timezone
from django.db.backends.signals import connection_created

logger = logging.getLogger(__name__)

# 在数据库连接创建后启用 SQLite WAL，提高并发写入能力
@receiver(connection_created)
def enable_sqlite_wal(sender, connection, **kwargs):
    try:
        if connection.vendor == 'sqlite':
            with connection.cursor() as cursor:
                cursor.execute('PRAGMA journal_mode=WAL;')
                cursor.execute('PRAGMA synchronous=NORMAL;')  # 减少写入阻塞，提高并发
                cursor.execute('PRAGMA busy_timeout=5000;')   # 5s 等待以避免锁错误
            # logger.info('SQLite WAL 模式已启用，设置 synchronous=NORMAL, busy_timeout=5000ms')
    except Exception as e:
        logger.warning(f'启用 SQLite WAL 失败: {e}')

from .models import Battle, BattleStatistics, WorldCupMatch


@receiver(post_save, sender=Battle)
def update_battle_statistics(sender, instance, created, **kwargs):
    """
    当Battle对象保存时自动更新相关用户的统计数据
    """
    # 只有当对战完成时才更新统计
    if instance.status != 'finished' or not instance.result:
        return

    # 自动计算精彩程度评分（如果还未计算过）
    if instance.excitement_calculated_at is None:
        try:
            instance.calculate_excitement_score()
            instance.update_excitement_status()
            instance.excitement_calculated_at = timezone.now()
            # 使用update避免递归调用信号
            Battle.objects.filter(id=instance.id).update(
                excitement_score=instance.excitement_score,
                is_exciting=instance.is_exciting,
                excitement_calculated_at=instance.excitement_calculated_at
            )
        except Exception as e:
            # 记录错误但不影响其他处理
            print(f"计算战斗 #{instance.id} 精彩程度评分时出错: {str(e)}")

    # 自己对战自己不计入统计
    if instance.player1 == instance.player2:
        return

    # 更新玩家1的统计
    update_user_statistics(instance.player1, instance, is_player1=True)

    # 更新玩家2的统计
    update_user_statistics(instance.player2, instance, is_player1=False)

    # 处理经验值奖励
    handle_battle_exp_reward(instance)

    # 更新相关的WorldCupMatch状态
    update_worldcup_match_status(instance)


def update_user_statistics(user, battle, is_player1=True):
    """
    更新指定用户的统计数据

    Args:
        user: 用户对象
        battle: 对战对象
        is_player1: 是否为玩家1
    """
    # 排除世界杯对战记录，世界杯对战不计入全局统计
    if battle.battle_type in ['worldcup_regular', 'worldcup_championship']:
        return

    # 获取或创建用户统计记录
    stats, created = BattleStatistics.objects.get_or_create(
        user=user,
        defaults={
            'total_battles': 0,
            'wins': 0,
            'losses': 0,
            'draws': 0,
            'total_score': 0,
            'average_score': 0.0,
            'best_score': 0,
            'current_rank': 0,
            'highest_rank': 0,
            'rating': 0,
        },
    )

    # 如果是新创建的统计记录，需要重新计算所有历史数据
    if created:
        recalculate_user_statistics(user)
        return

    # 避免重复统计同一战斗
    if stats.last_battle_at == battle.finished_at:
        return

    # 确定对战结果和得分
    if is_player1:
        user_score = battle.player1_score or 0
        if battle.result == 'player1_win':
            battle_result = 'win'
        elif battle.result == 'player2_win':
            battle_result = 'loss'
        else:
            battle_result = 'draw'
    else:
        user_score = battle.player2_score or 0
        if battle.result == 'player2_win':
            battle_result = 'win'
        elif battle.result == 'player1_win':
            battle_result = 'loss'
        else:
            battle_result = 'draw'

    # 更新统计数据
    stats.total_battles += 1
    stats.total_score += user_score
    stats.average_score = stats.total_score / stats.total_battles

    # 将每场得分累加到rating字段
    stats.rating += user_score

    if user_score > stats.best_score:
        stats.best_score = user_score

    if battle_result == 'win':
        stats.wins += 1
    elif battle_result == 'loss':
        stats.losses += 1
    elif battle_result == 'draw':
        stats.draws += 1

    stats.last_battle_at = battle.finished_at or timezone.now()

    # 更新详细统计数据（击杀、伤害、治疗等）
    if is_player1 and battle.player1_stats:
        player_stats = battle.player1_stats
        detailed_stats = {
            'kills': player_stats.get('stats', {}).get('kills', 0),
            'deaths': player_stats.get('stats', {}).get('deaths', 0),
            'totalDamageDealt': player_stats.get('stats', {}).get('totalDamageDealt', 0),
            'totalDamageReceived': player_stats.get('stats', {}).get('totalDamageReceived', 0),
            'totalHealing': player_stats.get('stats', {}).get('totalHealing', 0),
            'commandFailCount': player_stats.get('stats', {}).get('commandFailCount', 0),
            'rmb': player_stats.get('rmb', 0),
            'baseHealth': player_stats.get('baseHealth', 0),
        }
        stats.update_detailed_stats(detailed_stats)
    elif not is_player1 and battle.player2_stats:
        player_stats = battle.player2_stats
        detailed_stats = {
            'kills': player_stats.get('stats', {}).get('kills', 0),
            'deaths': player_stats.get('stats', {}).get('deaths', 0),
            'totalDamageDealt': player_stats.get('stats', {}).get('totalDamageDealt', 0),
            'totalDamageReceived': player_stats.get('stats', {}).get('totalDamageReceived', 0),
            'totalHealing': player_stats.get('stats', {}).get('totalHealing', 0),
            'commandFailCount': player_stats.get('stats', {}).get('commandFailCount', 0),
            'rmb': player_stats.get('rmb', 0),
            'baseHealth': player_stats.get('baseHealth', 0),
        }
        stats.update_detailed_stats(detailed_stats)
    else:
        # 如果没有详细统计数据，只保存基本统计
        stats.save()


def recalculate_user_statistics(user):
    """
    重新计算用户的所有统计数据

    Args:
        user: 用户对象
    """
    # 获取用户的所有已完成对战，排除自己对战自己的情况和世界杯对战
    battles = (
        Battle.objects.filter(models.Q(player1=user) | models.Q(player2=user), status='finished')
        .exclude(models.Q(player1=user, player2=user))
        .exclude(battle_type__in=['worldcup_regular', 'worldcup_championship'])
        .order_by('finished_at')
    )

    # 获取或创建统计记录
    stats, _ = BattleStatistics.objects.get_or_create(
        user=user,
        defaults={
            'total_battles': 0,
            'wins': 0,
            'losses': 0,
            'draws': 0,
            'total_score': 0,
            'average_score': 0.0,
            'best_score': 0,
            'current_rank': 0,
            'highest_rank': 0,
            'rating': 0,
        },
    )

    # 重置统计数据
    stats.total_battles = 0
    stats.wins = 0
    stats.losses = 0
    stats.draws = 0
    stats.total_score = 0
    stats.best_score = 0
    stats.last_battle_at = None

    # 遍历所有对战重新计算
    for battle in battles:
        is_player1 = battle.player1 == user

        # 确定对战结果和得分
        if is_player1:
            user_score = battle.player1_score or 0
            if battle.result == 'player1_win':
                battle_result = 'win'
            elif battle.result == 'player2_win':
                battle_result = 'loss'
            else:
                battle_result = 'draw'
        else:
            user_score = battle.player2_score or 0
            if battle.result == 'player2_win':
                battle_result = 'win'
            elif battle.result == 'player1_win':
                battle_result = 'loss'
            else:
                battle_result = 'draw'

        # 更新统计
        stats.total_battles += 1
        stats.total_score += user_score

        if user_score > stats.best_score:
            stats.best_score = user_score

        if battle_result == 'win':
            stats.wins += 1
        elif battle_result == 'loss':
            stats.losses += 1
        elif battle_result == 'draw':
            stats.draws += 1

        stats.last_battle_at = battle.finished_at or timezone.now()

    # 计算平均得分
    if stats.total_battles > 0:
        stats.average_score = stats.total_score / stats.total_battles
    else:
        stats.average_score = 0.0

    stats.save()


@receiver(post_delete, sender=Battle)
def handle_battle_deletion(sender, instance, **kwargs):
    """
    当Battle对象被删除时，重新计算相关用户的统计数据
    """
    if instance.status == 'finished' and instance.result:
        # 重新计算两个玩家的统计数据
        recalculate_user_statistics(instance.player1)
        recalculate_user_statistics(instance.player2)


# 用户创建时自动创建统计记录
@receiver(post_save, sender=User)
def create_user_statistics(sender, instance, created, **kwargs):
    """
    当新用户创建时，自动创建对应的统计记录
    """
    if created:
        BattleStatistics.objects.get_or_create(
            user=instance,
            defaults={
                'total_battles': 0,
                'wins': 0,
                'losses': 0,
                'draws': 0,
                'total_score': 0,
                'average_score': 0.0,
                'best_score': 0,
                'current_rank': 0,
                'highest_rank': 0,
                'rating': 0,
            },
        )


def handle_battle_exp_reward(battle):
    """处理战斗结束后的经验值奖励"""
    # 避免重复奖励，检查是否已经有经验值记录
    if ExpLog.objects.filter(user__in=[battle.player1, battle.player2], reason__contains=f'战斗#{battle.id}').exists():
        return

    # 根据战斗结果给予经验值奖励
    exp_rewards = calculate_battle_exp_reward(battle)

    # 给玩家1奖励经验值
    if exp_rewards['player1'] > 0:
        battle.player1.profile.add_exp(
            exp_rewards['player1'], f'战斗#{battle.id} - {get_result_description(battle.result, "player1")}'
        )

    # 给玩家2奖励经验值
    if exp_rewards['player2'] > 0:
        battle.player2.profile.add_exp(
            exp_rewards['player2'], f'战斗#{battle.id} - {get_result_description(battle.result, "player2")}'
        )


def calculate_battle_exp_reward(battle):
    """计算战斗经验值奖励"""
    base_exp = 50  # 基础经验值
    win_bonus = 30  # 胜利奖励
    draw_bonus = 15  # 平局奖励

    # 根据战斗类型调整经验值
    type_multiplier = {
        'ranked': 1.0,  # 排位赛正常经验
        'practice': 0.1,  # 练习赛减半
    }

    multiplier = type_multiplier.get(battle.battle_type, 1.0)

    if battle.result == 'player1_win':
        return {'player1': int((base_exp + win_bonus) * multiplier), 'player2': int(base_exp * multiplier)}
    elif battle.result == 'player2_win':
        return {'player1': int(base_exp * multiplier), 'player2': int((base_exp + win_bonus) * multiplier)}
    elif battle.result == 'draw':
        return {'player1': int((base_exp + draw_bonus) * multiplier), 'player2': int((base_exp + draw_bonus) * multiplier)}
    else:
        # 错误情况，不给经验值
        return {'player1': 0, 'player2': 0}


def get_result_description(result, player):
    """获取战斗结果描述"""
    if result == 'player1_win':
        return '胜利' if player == 'player1' else '失败'
    elif result == 'player2_win':
        return '胜利' if player == 'player2' else '失败'
    elif result == 'draw':
        return '平局'
    else:
        return '异常结束'


def update_worldcup_match_status(battle):
    """
    当Battle完成时，更新相关的WorldCupMatch状态
    """
    try:
        # 查找与此Battle关联的WorldCupMatch
        worldcup_match = WorldCupMatch.objects.filter(battle=battle).first()
        if worldcup_match:
            # 调用模型中的方法来更新状态
            worldcup_match.update_from_battle_result()
            print(f"已更新WorldCupMatch {worldcup_match.id} 的状态")
    except Exception as e:
        print(f"更新WorldCupMatch状态时出错: {e}")
